package engine.render;

import engine.scene.Tri;
import engine.util.DataUtil;
import java.nio.FloatBuffer;
import math.vector.vec2f;
import math.vector.vec3f;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;

public class VertexBuffer
{
    
    private static final int IND_VERT = 0;
    private static final int IND_NORMAL = 1;
    private static final int IND_TEXCOORD = 2;
    
    private static final int SIZE_POS = 3;
    private static final int SIZE_NORMAL = 3;
    private static final int SIZE_TEXCOORD = 2;
    private static final int FLOATS_PER_VERTEX = (
        VertexBuffer.SIZE_POS + VertexBuffer.SIZE_NORMAL + VertexBuffer.SIZE_TEXCOORD
    );
    private static final int FLOATS_PER_TRI = 3 * VertexBuffer.FLOATS_PER_VERTEX;
    
    
    private int bufferID;
    
    private int numTriangles;
    
    private FloatBuffer bufferVertex; // [ Vx, Vy, Vz, Nx, Ny, Nz, Tx, Tz ]
    //<editor-fold defaultstate="collapsed" desc="addVert">
    private void addVert(vec3f vert)
    {
        this.bufferVertex.put(vert.x);
        this.bufferVertex.put(vert.y);
        this.bufferVertex.put(vert.z);
    }
    //</editor-fold>
    //<editor-fold defaultstate="collapsed" desc="addNorm">
    private void addNorm(vec3f norm)
    {
        this.bufferVertex.put(norm.x);
        this.bufferVertex.put(norm.y);
        this.bufferVertex.put(norm.z);
    }
    //</editor-fold>
    //<editor-fold defaultstate="collapsed" desc="addTexCoord">
    private void addTexCoord(vec2f texCoord)
    {
        this.bufferVertex.put(texCoord.x);
        this.bufferVertex.put(texCoord.y);
    }
    //</editor-fold>
    //<editor-fold defaultstate="collapsed" desc="addTri">
    private void addTri(Tri tri)
    {
        if (tri != null)
        {
            for (int i = 0; i < Tri.NUM_VERTICES; i++)
            {
                this.addVert(tri.verts[i]);
                this.addNorm(tri.norms[i]);
                this.addTexCoord(tri.texCoords[i]);
            }
        }
    }
    //</editor-fold>
    
    public VertexBuffer(Tri[] tris)
    {
        this.numTriangles = tris.length;
        this.bufferVertex = DataUtil.get().reserveDataFloat(
            VertexBuffer.FLOATS_PER_TRI * this.numTriangles
        );
        for (int i = 0; i < this.numTriangles; i++)
        {
            this.addTri(tris[i]);
        }
        this.bufferVertex.flip();
        this.bufferID = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, this.bufferID);
        glBufferData(GL_ARRAY_BUFFER, this.bufferVertex, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind the array buffer
    }
    
    public void render()
    {
        glBindBuffer(GL_ARRAY_BUFFER, this.bufferID);
        
        glVertexAttribPointer(
            VertexBuffer.IND_VERT, 
            VertexBuffer.SIZE_POS, 
            GL_FLOAT, 
            false, 
            32, 
            0L
        );
        glVertexAttribPointer(
            VertexBuffer.IND_NORMAL, 
            VertexBuffer.SIZE_NORMAL, 
            GL_FLOAT, 
            true, 
            32, 
            12L
        );
        glVertexAttribPointer(
            VertexBuffer.IND_TEXCOORD, 
            VertexBuffer.SIZE_TEXCOORD, 
            GL_FLOAT, 
            false, 
            32, 
            24L
        );
        
        glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind the array buffer
        
        glEnableVertexAttribArray(VertexBuffer.IND_VERT);
        glEnableVertexAttribArray(VertexBuffer.IND_NORMAL);
        glEnableVertexAttribArray(VertexBuffer.IND_TEXCOORD);
        
        glDrawArrays(
            GL_TRIANGLES, // Data grouping type
            0, // Offset value
            3 * this.numTriangles // Number of data group vertices
        );
        
        glDisableVertexAttribArray(VertexBuffer.IND_VERT);
        glDisableVertexAttribArray(VertexBuffer.IND_NORMAL);
        glDisableVertexAttribArray(VertexBuffer.IND_TEXCOORD);
    }
    
    public void destroy()
    {
        glDeleteBuffers(this.bufferID);
        this.numTriangles = 0;
        this.bufferVertex.clear();
        this.bufferVertex = null;
    }
    
}
